package com.acron.xrpc.registry;

import com.acron.xrpc.protool.InvokeProtocol;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;

import java.io.File;
import java.lang.reflect.Method;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 注册实现
 * 扫描类路径下可用接口，并注册接口实现到注册表
 * Created by acron on 2022/2/19.
 */
public class RpcHandler extends ChannelInboundHandlerAdapter {

    /**
     * 注册定义
     */
    private volatile static List<String> registryDefines = new ArrayList<>();

    /**
     * 注册表
     */

    private volatile static Map<String, Object> registryMap = new ConcurrentHashMap<>();

    public RpcHandler() {
        scanClassPath("com.acron.xrpc.provider");
        doRegistry();
    }

    private void doRegistry() {
        // 注册
        if (registryDefines.isEmpty()) {
            return;
        }
        for (String registryDefine : registryDefines) {
            try {
                // 反射创建实例对象
                Class<?> clazz = Class.forName(registryDefine);
                if(clazz.isInterface()) {
                    continue;
                }
                Class<?> interf = clazz.getInterfaces()[0];
                // 设置注册表,K--服务接口名称，V--实现实例
                registryMap.put(interf.getName(), clazz.newInstance());
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            } catch (InstantiationException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        }
    }

    private void scanClassPath(String packageName) {
        // 网络地址找资源
        URL url = this.getClass().getClassLoader().getResource(packageName.replaceAll("\\.", "/"));
        // 转换为文件操作
        File dir = new File(url.getFile());
        for (File file : dir.listFiles()) {
            if (file.isDirectory()) {
                // 是文件夹，继续递归扫描
                scanClassPath(packageName + "." + file.getName());
            } else {
                // 是文件，加入注册定义
                String registryDefineName = packageName + "." + file.getName().replace(".class", "").trim();
                registryDefines.add(registryDefineName);
            }
        }
    }


    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        // 解析客户端请求，实际调用服务端方法（用反射本地调用模拟远程调用）发送调用结果给客户端
        // 返回结果
        Object result = new Object();
        // 解析调用协议
        InvokeProtocol protocol = (InvokeProtocol) msg;
        // 校验是否注册
        if (registryMap.containsKey(protocol.getClassName())) {
            // 反射调用本地服务
            Object clazz = registryMap.get(protocol.getClassName());
            Method method = clazz.getClass().getMethod(protocol.getMethodName(), protocol.getParams());
            result = method.invoke(clazz, protocol.getValues());
        }
        if (Objects.isNull(result)) {
            result = new Object();
        }
        // 调用结果返回给客户端
        ctx.write(result);
    }

    @Override
    public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
        ctx.flush();
        ctx.close();
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        System.out.println("rpc registry error");
        cause.printStackTrace();
        ctx.close();
    }
}
